// http://stackoverflow.com/questions/8588563/adding-custom-properties-to-a-function
// standard function properties (arguments, name, caller & length) cannot be overwritten

if (false) {
	// Way 1 : adding properties while running the function
	var fun1 = function() {
		fun1.name = 'Tom';
		fun1.name2 = 'John';
		return 'Beep';
	};
	console.log('fun1.name : ' + fun1.name);
	console.log('fun1.name2 : ' + fun1.name2);
	console.log('fun1() : ' + fun1()); //exe 
	console.log('fun1.name : ' + fun1.name);
	console.log('fun1.name2 : ' + fun1.name2);
	// Output :
	// fun1.name : 
	// fun1.name2 : undefined
	// fun1() : Beep
	// fun1.name : 
	// fun1.name2 : John
}

if (false) {
	// way 1 alternate : declare
	function fun2() {
		fun2.name = 'Tom';
		fun2.name2 = 'John';
		return 'Beep';
	};
	console.log('fun2.name : ' + fun2.name);
	console.log('fun2.name2 : ' + fun2.name2);
	console.log('fun2() : ' + fun2());
	console.log('fun2.name : ' + fun2.name);
	console.log('fun2.name2 : ' + fun2.name2);
	// 	Output :
	// fun2.name : 
	// fun2.name2 : undefined
	// fun2() : Beep
	// fun2.name : 
	// fun2.name2 : John 
}

if (false) {
	// way 1 alternate2
	var fun3 = function f() {
		f.name = 'Tom';
		f.name2 = 'John';
		return 'Beep';
	};

	console.log('fun3.name : ' + fun3.name);
	console.log('fun3.name2 : ' + fun3.name2);
	console.log('fun3() : ' + fun3());
	console.log('fun3.name : ' + fun3.name);
	console.log('fun3.name2 : ' + fun3.name2);
	// 	Output :
	// fun3.name : f
	// fun3.name2 : undefined
	// fun3() : Beep
	// fun3.name : f
	// fun3.name2 : John 
}


if (false) {
	// Way 2 : adding properties after defining the function :
	function fun4() {
		return 'Beep';
	};

	fun4.name = 'Tom';
	fun4.name2 = 'John';

	console.log('fun4.name : ' + fun4.name);
	console.log('fun4.name2 : ' + fun4.name2);
	console.log('fun4() : ' + fun4());
	console.log('fun4.name : ' + fun4.name);
	console.log('fun4.name2 : ' + fun4.name2);
	// Output :
	// fun4.name : fun4
	// fun4.name2 : John
	// fun4() : Beep
	// fun4.name : fun4
	// fun4.name2 : John 
}

if (false) {
	// Way 3 : wrap your function in anonymous function :
	var param = {
		'name': 'Tom',
		'name2': 'John'
	};
	// fun5 = immdiately execute function
	var fun5 = (
		function(args) {
			var f = function() {
				return 'Beep';
			};
			for (i in args) {
				f[i] = args[i];
			}
			return f;
		}(param));

	console.log('fun5.name : ' + fun5.name);
	console.log('fun5.name2 : ' + fun5.name2);
	console.log('fun5() : ' + fun5());
	console.log('fun5.name : ' + fun5.name);
	console.log('fun5.name2 : ' + fun5.name2);
	// Output :
	// fun5.name : 
	// fun5.name2 : John
	// fun5() : Beep
	// fun5.name : 
	// fun5.name2 : John
}

if (false) {
	// Way 4 : add an 'extend' function to your function, 
	//that adds the properties of an object to itself one by one :
	var fun6 = function() {
		return 'Beep';
	};
	fun6.extend = function(args) {
		for (i in args) {
			this[i] = args[i];
		}
		return this;
	}
	fun6.extend({
		'name': 'Tom',
		'name2': 'John'
	});
	console.log('fun6.name : ' + fun6.name);
	console.log('fun6.name2 : ' + fun6.name2);
	console.log('fun6() : ' + fun6());
	console.log('fun6.name : ' + fun6.name);
	console.log('fun6.name2 : ' + fun6.name2);
	// Output :
	// fun6.name : 
	// fun6.name2 : John
	// fun6() : Beep
	// fun6.name : 
	// fun6.name2 : John
}

if (false) {
	// Way 5 : Make a generic 'extend' function :
	var extend = function(obj, args) {
		if (Array.isArray(args) || (args !== null && typeof args === 'object')) {
			for (i in args) {
				obj[i] = args[i];
			}
		}
		return obj;
	}

	var fun7 = extend(
		function() {
			return 'Beep';
		}, {
			'name': 'Tom',
			'name2': 'John'
		}
	);
	console.log('fun7.name : ' + fun7.name);
	console.log('fun7.name2 : ' + fun7.name2);
	console.log('fun7() : ' + fun7());
	console.log('fun7.name : ' + fun7.name);
	console.log('fun7.name2 : ' + fun7.name2);
	// Output :
	// fun7.name : 
	// fun7.name2 : John
	// fun7() : Beep
	// fun7.name : 
	// fun7.name2 : John
}


if (false) {
	// Way 6 : Create an extendableFunction object and
	// use it to attach an extend function to a function :
	var extendableFunction = (function() {
		var extend = function(args) {
			if (Array.isArray(args) || (args !== null && typeof args === 'object')) {
				for (i in args) {
					this[i] = args[i];
				}
			}
			return this;
		};
		var ef = function(v, args) {
			v.extend = extend;
			return v.extend(args);
		};
		ef.create = function(v, args) {
			return new this(v, args);
		};
		return ef;
	})();

	var fun8 = extendableFunction.create(
		function() {
			return 'Beep';
		}, {
			'name': 'Tom',
			'name2': 'John'
		}
	);

	console.log('fun8.name : ' + fun8.name);
	console.log('fun8.name2 : ' + fun8.name2);
	console.log('fun8() : ' + fun8());
	console.log('fun8.name : ' + fun8.name);
	console.log('fun8.name2 : ' + fun8.name2);
	// Output :
	// fun8.name : 
	// fun8.name2 : John
	// fun8() : Beep
	// fun8.name : 
	// fun8.name2 : John 
}

if (true) {
	//	Way 7 : Add an 'extend' function to the Function prototype :
	Function.prototype.extend = function(args) {
		if (Array.isArray(args) || (args !== null && typeof args === 'object')) {
			for (i in args) {
				this[i] = args[i];
			}
		}
		return this;
	};

	var fun9 = function() {
		return 'Beep';
	}.extend({
		name: 'Tom',
		name2: 'John'
	});

	console.log('fun9.name : ' + fun9.name);
	console.log('fun9.name2 : ' + fun9.name2);
	console.log('fun9() : ' + fun9());
	console.log('fun9.name : ' + fun9.name);
	console.log('fun9.name2 : ' + fun9.name2);
	// Output:

	// fun9.name:
	// fun9.name2: John
	// fun9(): Beep
	// fun9.name:
	// fun9.name2: John
}